package tech.darkblue.rpcui;

import java.io.File;
import java.io.IOException;
import java.util.Observable;
import java.util.Properties;

import org.apache.commons.lang3.StringUtils;
import org.apache.log4j.Level;
import org.apache.log4j.LogManager;
import org.eclipse.swt.SWT;
import org.eclipse.swt.events.DisposeEvent;
import org.eclipse.swt.events.DisposeListener;
import org.eclipse.swt.events.KeyAdapter;
import org.eclipse.swt.events.KeyEvent;
import org.eclipse.swt.events.SelectionAdapter;
import org.eclipse.swt.events.SelectionEvent;
import org.eclipse.swt.graphics.FontData;
import org.eclipse.swt.layout.FillLayout;
import org.eclipse.swt.widgets.Display;
import org.eclipse.swt.widgets.FontDialog;
import org.eclipse.swt.widgets.Menu;
import org.eclipse.swt.widgets.MenuItem;
import org.eclipse.swt.widgets.Shell;
import org.eclipse.swt.widgets.Text;

import tech.darkblue.rpcui.config.Configurations;
import tech.darkblue.rpcui.extend.ConfigObserver;
import tech.darkblue.rpcui.extend.LoggerPrintStream;
import tech.darkblue.rpcui.menu.about.AboutDialog;
import tech.darkblue.rpcui.menu.run.RunAsDialog;
import tech.darkblue.rpcui.menu.run.RunConfigDialog;
import tech.darkblue.rpcui.menu.setup.ApiJarFileDialog;
import tech.darkblue.rpcui.menu.setup.SettingDialog;
import tech.darkblue.rpcui.util.SwtUtils;

public class Main implements ConfigObserver {

    protected Shell shellRpcUI;

    private Text txtLogger;

    private boolean restartOnClosed;

    /**
     * Launch the application.
     * @param args
     */
    public static void main(String[] args) {
        try {
            String log4jConfigUrl = new File(Configurations.LOG4J_CONFIG).toURI().toString();
            System.setProperty("log4j.configuration", log4jConfigUrl);
            Main rpcUIMain = new Main();
            rpcUIMain.open();
        } catch (Throwable e) {
            e.printStackTrace();
        }
    }

    public Main() {
        restartOnClosed = false;
        Configurations.CONFIG_OBSERVER.addObserver(this);
    }

    /**
     * Open the window.
     */
    public void open() {
        Display display = Display.getDefault();
        createContents();
        shellRpcUI.open();
        shellRpcUI.layout();
        while (!shellRpcUI.isDisposed()) {
            if (!display.readAndDispatch()) {
                display.sleep();
            }
        }
    }

    /**
     * Create contents of the window.
     */
    protected void createContents() {
        shellRpcUI = new Shell();
        shellRpcUI.setImages(Configurations.DEFAULT_ICON_IMAGES);
        shellRpcUI.addDisposeListener(new DisposeListener() {
            public void widgetDisposed(DisposeEvent e) {
                Configurations.CONFIG_OBSERVER.deleteObserver(Main.this);
                LogManager.getRootLogger().setLevel(Level.OFF);
                if (restartOnClosed) {
                    String runFilePath = new File(Configurations.DIR_BASE, "run.bat").getPath();
                    try {
                        Runtime.getRuntime().exec(new String[] { "cmd", "/c", runFilePath });
                    } catch (IOException ex) {
                        ex.printStackTrace();
                    }
                }
                System.exit(0);
            }
        });
        shellRpcUI.setSize(1024, 576);
        shellRpcUI.setText("Dubbo - RpcUI4D");
        shellRpcUI.setLayout(new FillLayout(SWT.HORIZONTAL));

        Menu menu = new Menu(shellRpcUI, SWT.BAR);
        shellRpcUI.setMenuBar(menu);

        MenuItem mntmSetup = new MenuItem(menu, SWT.CASCADE);
        mntmSetup.setText("Setup");

        Menu menuSetup = new Menu(mntmSetup);
        mntmSetup.setMenu(menuSetup);

        MenuItem mntmSetting = new MenuItem(menuSetup, SWT.NONE);
        mntmSetting.addSelectionListener(new SelectionAdapter() {
            @Override
            public void widgetSelected(SelectionEvent e) {
                SettingDialog dlgSetting = new SettingDialog(shellRpcUI, SwtUtils.DIALOG_DEFAULT_STYLE);
                try {
                    dlgSetting.open();
                } catch (Throwable ex) {
                    ex.printStackTrace();
                }
            }
        });
        mntmSetting.setText("Settings...");

        MenuItem mntmApiJarFile = new MenuItem(menuSetup, SWT.NONE);
        mntmApiJarFile.addSelectionListener(new SelectionAdapter() {
            @Override
            public void widgetSelected(SelectionEvent e) {
                ApiJarFileDialog dlgApiJarFile = new ApiJarFileDialog(shellRpcUI, SwtUtils.DIALOG_DEFAULT_STYLE);
                try {
                    dlgApiJarFile.open();
                } catch (Throwable ex) {
                    ex.printStackTrace();
                }
            }
        });
        mntmApiJarFile.setText("Api Jar Files...");

        new MenuItem(menuSetup, SWT.SEPARATOR);

        MenuItem mntmRestart = new MenuItem(menuSetup, SWT.NONE);
        mntmRestart.addSelectionListener(new SelectionAdapter() {
            @Override
            public void widgetSelected(SelectionEvent e) {
                restartOnClosed = true;
                shellRpcUI.close();
                shellRpcUI.dispose();
            }
        });
        mntmRestart.setText("Restart");

        new MenuItem(menuSetup, SWT.SEPARATOR);

        MenuItem mntmExit = new MenuItem(menuSetup, SWT.NONE);
        mntmExit.addSelectionListener(new SelectionAdapter() {
            @Override
            public void widgetSelected(SelectionEvent e) {
                shellRpcUI.close();
                shellRpcUI.dispose();
            }
        });
        mntmExit.setText("Exit");

        MenuItem mntmRun = new MenuItem(menu, SWT.CASCADE);
        mntmRun.setText("Run");

        Menu menuRun = new Menu(mntmRun);
        mntmRun.setMenu(menuRun);

        MenuItem mntmRunAs = new MenuItem(menuRun, SWT.NONE);
        mntmRunAs.addSelectionListener(new SelectionAdapter() {
            @Override
            public void widgetSelected(SelectionEvent e) {
                RunAsDialog dlgRunAs = new RunAsDialog(shellRpcUI, SwtUtils.DIALOG_DEFAULT_STYLE);
                try {
                    dlgRunAs.open();
                } catch (Throwable ex) {
                    ex.printStackTrace();
                }
            }
        });
        mntmRunAs.setText("Run As...");

        MenuItem mntmRunConfiguration = new MenuItem(menuRun, SWT.NONE);
        mntmRunConfiguration.addSelectionListener(new SelectionAdapter() {
            @Override
            public void widgetSelected(SelectionEvent e) {
                try {
                    RunConfigDialog dlgRunConfig = new RunConfigDialog(shellRpcUI, SwtUtils.DIALOG_DEFAULT_STYLE);
                    dlgRunConfig.open();
                } catch (Throwable ex) {
                    ex.printStackTrace();
                }
            }
        });
        mntmRunConfiguration.setText("Run Configurations...");

        MenuItem mntmHelp = new MenuItem(menu, SWT.CASCADE);
        mntmHelp.setText("Help");

        Menu menuHelp = new Menu(mntmHelp);
        mntmHelp.setMenu(menuHelp);

        MenuItem mntmSetFont = new MenuItem(menuHelp, SWT.NONE);
        mntmSetFont.addSelectionListener(new SelectionAdapter() {
            @Override
            public void widgetSelected(SelectionEvent e) {
                try {
                    Properties currentProperty = Configurations.getCurrentProperty();
                    String fontData = currentProperty.getProperty("app.fontData");
                    FontDialog dlgFont = new FontDialog(shellRpcUI, SWT.NONE);
                    if (StringUtils.isNotBlank(fontData)) {
                        dlgFont.setFontList(new FontData[] { new FontData(fontData) });
                    }
                    FontData dlgFontData = dlgFont.open();

                    if (dlgFontData != null && !dlgFontData.toString().equals(fontData)) {
                        fontData = dlgFontData.toString();
                        Configurations.setCurrentFont(fontData);
                        currentProperty.setProperty("app.fontData", fontData);
                        Configurations.setCurrentProperty(currentProperty);;
                        Configurations.CONFIG_OBSERVER.notifyObservers();
                    }
                } catch (Exception ex) {
                    ex.printStackTrace();
                }
            }
        });
        mntmSetFont.setText("Set Font...");

        MenuItem mntmClearConsole = new MenuItem(menuHelp, SWT.NONE);
        mntmClearConsole.addSelectionListener(new SelectionAdapter() {
            @Override
            public void widgetSelected(SelectionEvent e) {
                txtLogger.setText("");
            }
        });
        mntmClearConsole.setText("Clear Console");

        new MenuItem(menuHelp, SWT.SEPARATOR);

        MenuItem mntmAbout = new MenuItem(menuHelp, SWT.NONE);
        mntmAbout.addSelectionListener(new SelectionAdapter() {
            @Override
            public void widgetSelected(SelectionEvent e) {
                AboutDialog dlgAbout = new AboutDialog(shellRpcUI, SwtUtils.DIALOG_DEFAULT_STYLE);
                dlgAbout.open();
            }
        });
        mntmAbout.setText("About");

        txtLogger = new Text(shellRpcUI, SWT.BORDER | SWT.MULTI | SWT.H_SCROLL | SWT.V_SCROLL);
        txtLogger.addKeyListener(new KeyAdapter() {
            @Override
            public void keyPressed(KeyEvent e) {
                SwtUtils.bindTextShortcutKey(e, txtLogger);
            }
        });
        txtLogger.setFont(Configurations.getCurrentFont());

        LoggerPrintStream loggerPrintStream = new LoggerPrintStream(System.out, txtLogger);
        System.setOut(loggerPrintStream);
        System.setErr(loggerPrintStream);
        System.out.println("RpcUI4D has started...");
    }

    @Override
    public void update(Observable o, Object arg) {
        txtLogger.setFont(Configurations.getCurrentFont());
    }
}
